package com.czh.framework.security.provider;

import com.czh.common.constant.CacheConstants;
import com.czh.common.date.RedisCache;
import com.czh.framework.security.authentication.JwtAuthentication;
import com.czh.framework.security.web.UserDetailsEntity;
import com.czh.framework.security.web.service.TokenService;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;

import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.czh.common.constant.CacheConstants.LOGIN_REDIS_KEY;
import static com.czh.common.constant.CacheConstants.TOKEN_MIN_TIME_OUT_MINUTE;

public class JwtAuthenticationProvider implements AuthenticationProvider {

    RedisCache redisCache;

    public JwtAuthenticationProvider(RedisCache redisCache) {
        this.redisCache = redisCache;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        JwtAuthentication jwtAuthentication = (JwtAuthentication) authentication;
        String token = jwtAuthentication.getToken();
        Map<String, Object> redisKeyMap = null;

        redisKeyMap = TokenService.parseToken(token);


        String  redisKey = (String) redisKeyMap.get(LOGIN_REDIS_KEY);

        UserDetailsEntity userDetails = redisCache.getCacheObject(redisKey);

        if (userDetails == null) {
            throw new BadCredentialsException("token 已经过期");
        }

        long minutes = redisCache.getExpire(redisKey) / TokenService.MINUTE;

        //剩余过期时间 少了就给他加点时间
        if(minutes < TOKEN_MIN_TIME_OUT_MINUTE){
            redisCache.redisTemplate.expire(redisKey, CacheConstants.TOKEN_TIME_OUT_MINUTE, TimeUnit.MINUTES);
        }

        /**
         * 此处一定要是三个参数  你点进去看看构造函数   那个两个参数的 他妈的设置了 false 真无语
         */
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(userDetails
                        ,userDetails.getPassword(),
                        userDetails.getAuthorities());

        /**
         * We start by creating an empty SecurityContext.
         * You should create a new SecurityContext instance
         * instead of using SecurityContextHolder.getContext().setAuthentication(authentication)
         * to avoid race conditions across multiple threads.
         */
        final SecurityContext emptyContext = SecurityContextHolder.createEmptyContext();
        emptyContext.setAuthentication(authenticationToken);
        SecurityContextHolder.setContext(emptyContext);

        return authenticationToken;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return JwtAuthentication.class.isAssignableFrom(authentication);
    }
}
